﻿#include "ocrtest.h"
#include "ui_ocrtest.h"
#include <QFileDialog>
#include <QFileDialog>
#include <QDebug>


#include "OCR/PassImageProc.h"
#include <string>
#ifdef _MSC_VER
#include <io.h>
#include <process.h>
#endif
#include <ctype.h>
#include <time.h>
#include <fstream>
#include <chrono>

#include "ED_Lib-master/EDLib.h"

#include "shape_based_matching/line2Dup.h"

#include <RectifyPureC.h>
#include <RectifyWithOpencv.h>

using namespace cv;
using namespace std;

//#define CAM
#define PIC

bool bInit = true;
bool bStopRecognize = false;
bool bContinueProc = true;
std::vector<cv::Mat> g_ResultImgs;
std::vector<std::string> g_PassNumberArray;
std::vector<std::string> g_PassNameArray;
std::vector<std::string> g_TextArray;

std::vector<cv::Vec4i> g_lines;

clock_t start, finish;
double  duration;

#ifdef _MSC_VER
///调整图片分辨率
bool SetResolution(const char* path, int iResolution) {
    FILE * file = fopen(path, "rb+");// - 打开图片文件
    if (!file)return false;
    int len = _filelength(_fileno(file));// - 获取文件大小
    char* buf = new char[len];
    fread(buf, sizeof(char), len, file);// - 将图片数据读入缓存
    char * pResolution = (char*)&iResolution;// - iResolution为要设置的分辨率的数值，如72dpi
                                             // - 设置JPG图片的分辨率
    buf[0x0D] = 1;// - 设置使用图片密度单位
                  // - 水平密度，水平分辨率
    buf[0x0E] = pResolution[1];
    buf[0x0F] = pResolution[0]; 	// - 垂直密度，垂直分辨率
    buf[0x10] = pResolution[1];
    buf[0x11] = pResolution[0];  	// - 将文件指针移动回到文件开头
    fseek(file, 0, SEEK_SET); 	// - 将数据写入文件，覆盖原始的数据，让修改生效
    fwrite(buf, sizeof(char), len, file);
    fclose(file);
    return true;
}

///验证护照编码
byte Passport_checkSumSubString(byte *src, int len)
{
    int i, chk = 0;
    byte wmap[] = { 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35 };
    byte xmap[] = { 0,1,2,3,4,5,6,7,8,9 };
    byte cmap[] = { 7,3,1 };
    int cmapindex = 0;
    for (i = 0; i<len; i++)
    {
        if ((src[i] >= 'A') && (src[i] <= 'Z'))
        {
            chk += wmap[src[i] - 'A'] * cmap[cmapindex++];
        }
        else if ((src[i] >= '0') && (src[i] <= '9'))
        {
            chk += xmap[src[i] - '0'] * cmap[cmapindex++];
        }
        else
        {
            continue;
        }
        cmapindex = cmapindex % 3;
    }

    return (byte)(chk % 10 + '0');
}

///护照冗余校验
bool PassPortCheckCRC(const char *s)
{
    int len = strlen(s);
    if (len<28)return false;
    if (*s != 'E')return false;
    /*char subs[29] = { '\0' };
    strncpy(subs, s, 28);

    //---第一串校验  护照号
    //E006621742CHN0811220H1706192MNPEHPKGHILLA076

    //E006621742
    char Bu[20] = {'\0'};
    strncpy(Bu, subs, 12);
    byte bCrc = Passport_checkSumSubString((byte *)Bu, 9);
    if (bCrc != Bu[9])return  false;
    //0811220
    memset(Bu, '\0', 20);
    strncpy(Bu, subs+13, 7);
    bCrc = Passport_checkSumSubString((byte *)Bu, 6);
    if (bCrc != Bu[6])return  false;
    //1706192
    memset(Bu, '\0', 20);
    strncpy(Bu, subs + 21, 7);
    bCrc = Passport_checkSumSubString((byte *)Bu, 6);
    if (bCrc != Bu[6])return  false;*/

    return true;
}

///名字校验
bool NameCheck(const char *s)
{
    int len = strlen(s);
    if (len < 5)
        return false;
    if (*s != 'P')
        return false;
    /*const char *p = strchr(s, '<');
    if (p == 0)
    return false;
    bool isAlpa = true;
    int prenum = p - s;
    for (int i = 0; i < prenum; i++) {
    if (!isalpha(*(s + i))) {
    isAlpa = false;
    break;
    }
    }
    if (!isAlpa)
    return false;
    if (*(p + 1) != '<' || !isalpha(*(p + 2)))
    return false;
    if (*(s + len - 3) != '<')
    return false;
    */
    return true;
}

///港澳通行证
bool GangaoPass(const char *s)
{
    //CSC624902070220802807120406
    int len = strlen(s);
    if (len<27)return false;
    //if(s.contains("CS")) return true;
    char ss[4] = { '\0' };
    strncpy(ss, s, 2);
    if (!(isalpha(ss[0]) && isalnum(ss[1])))
        return false;

    char Bu[20] = { '\0' };
    strncpy(Bu, s, 10);
    byte bCrc = Passport_checkSumSubString((byte *)Bu, 9);
    if (bCrc != Bu[9])
        return  false;
    // C62490207
    int n = 2;
    n += 10;

    memset(Bu, '\0', 20);
    strncpy(Bu, s + 12, 7);
    bCrc = Passport_checkSumSubString((byte *)Bu, 6);
    if (bCrc != Bu[6])
        return  false;
    memset(Bu, '\0', 20);
    strncpy(Bu, s + 19, 7);
    bCrc = Passport_checkSumSubString((byte *)Bu, 6);
    if (bCrc != Bu[6])
        return  false;
    return true;
}
#endif

void trim(std::string &s)
{
    int index = 0;
    if (!s.empty()) {
        while ((index = s.find(' ', index)) != std::string::npos) {
            s.erase(index, 1);
        }
    }
}


OcrTest::OcrTest(QWidget *parent) :
    QDialog(parent),
    //GBaseClass(),
    ui(new Ui::OcrTest)
{
    ui->setupUi(this);
}

OcrTest::~OcrTest()
{
    delete ui;
}

void OcrTest::on_pushButton_clicked()
{
    PassImageProc preProc;
    cv::Mat image;
    std::vector<cv::Mat> procImgs;

    clock_t total_start, total_end;
    clock_t detect_start, detect_end;

#ifdef CAM
    VideoCapture cap(0);

    cap.set(CV_CAP_PROP_FRAME_WIDTH, 1600);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 1200);

    if (!cap.isOpened()) {
        std::cout << "read camera error!" << std::endl;
        system("pause");
        return -1;
    }
    while (true) {
        total_start = clock();

        clock_t readImg_start, readImg_end;
        readImg_start = clock();

        cap.read(image);

        readImg_end = clock();
        std::cout << "Read image time: " << readImg_end - readImg_start << "ms" << std::endl;

        if (image.empty())
        {
            std::cout << "Frame get failed!" << std::endl;
            continue;
        }

        //Mat *pDstImg = new Mat(frame.rows, frame.cols, frame.type());
        //frame.copyTo(*pDstImg);
        //Mat srcFrame = *((Mat *)pDstImg);

        detect_start = clock();

        preProc.imgProc(image, Size(28, 8));
        procImgs = preProc.getResultImageArray();

        detect_end = clock();
        std::cout << "   Detect time: " << detect_end - detect_start << "ms" << std::endl;

        imshow("frame", image);
        char c = waitKey(1);
        if (c == 27)
            break;

        total_end = clock();
        std::cout << "    Total time: " << total_end - total_start << "ms" << std::endl;
    }
    cap.release();
    destroyAllWindows();
#endif // CAM

#ifdef PIC
    string imageList = "pics_new.txt";
    //string imageList = "pics_pp.txt";
    //string imageList = "pics.txt";
    std::ifstream finImage(imageList, std::ios::in);
    string line;

    while (getline(finImage, line))
    {
        std::cout << line << std::endl;
        image = imread(line);
        preProc.imgProc(image, Size(28, 8));
        procImgs = preProc.getResultImageArray();
        char c = waitKey(0) & 0xFF;
        if (c == 'q')
            break;
    }
#endif // PIC
}

void OcrTest::on_OpenImage_clicked()
{
    PassImageProc preProc;    

    QString strFilePath = QFileDialog::getOpenFileName();

    if (!strFilePath.isEmpty())
    {
        std::string item = strFilePath.toStdString();

        try {
            ProcImageMap["ImImage"] = cv::imread(item);
        } catch (cv::Exception &e) {
            qDebug() <<"imread:"<< e.what();
            return ;
        }

        if(!ProcImageMap["ImImage"].empty())
        {
            preProc.imgProc(ProcImageMap["ImImage"], Size(28, 8));
            auto tmpVec = preProc.getResultImageArray();
            for(unsigned int ind=0; ind<tmpVec.size(); ind++ )
            {
               ProcImageMap[std::string("proc_")+ std::to_string(ind)] = tmpVec[ind];
            }
        }

        emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
    }
}

void OcrTest::on_GetPoint_clicked()
{
    QString strFilePath = QFileDialog::getOpenFileName();

    if (!strFilePath.isEmpty())
    {
        std::string item = strFilePath.toStdString();

        try {
             std::chrono::time_point<std::chrono::high_resolution_clock> TimeStart(std::chrono::high_resolution_clock::now());

            Mat InImage = cv::imread( item, IMREAD_COLOR );
            //imshow("In", tmpImage);
            cv::Mat TmpImage, BinImage;
            //unevenLightCompensate( tmpImage, 32 );
            //imshow("In1", tmpImage);

            cv::bilateralFilter(InImage, TmpImage, 5, 30, 30);
            //cv::Canny(TmpImage, BinImage, 50, 100);
            cv::cvtColor(TmpImage, BinImage, COLOR_BGR2GRAY);
            cv::threshold(BinImage, BinImage, 70, 1, cv::THRESH_TRIANGLE);

            //Mat element = getStructuringElement(MORPH_RECT, Size(3, 3) ); // 5、高级形态学变化，闭操作
            //cv::morphologyEx( BinImage,BinImage, MORPH_CLOSE, element);

           Mat ThinImage = thinImage(BinImage);

           BinImage = ThinImage * 255;
            //cv::threshold(tmpImage, BinImage, 80, 255, cv::THRESH_TRIANGLE);

//            adaptiveThreshold( tmpImage, BinImage, 255, ADAPTIVE_THRESH_MEAN_C,
//                               THRESH_BINARY, 35, 0);
            //emit ShowImageSig(BinImage, "BinImage");
            //waitKey();
            imshow("BinImage", BinImage);
            imshow("ThinImage", ThinImage);


            std::vector< std::vector<cv::Point> > contours;
            vector<cv::Vec4i> hierarchy;
            findContours(BinImage, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));

            Mat DrawImage = InImage.clone();

            for(size_t idx=0; idx<contours.size(); idx++)
            {
                if(contours[idx].size() < 50)
                {
                    continue;
                }

                Scalar LineColor(RNG(255), RNG(255), RNG(255));
                drawContours(DrawImage, contours, idx, LineColor);

                //遍历轮廓，求出所有支撑角度
                vector<Point> sharpContours = findSharpCorners(contours[idx]);
                for (int i = 0; i < sharpContours.size(); i++)
                {
                    circle(DrawImage, sharpContours[i], 5, LineColor, 2);
                }
            }

            long long CurUs = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - TimeStart).count() / 1000.f;
            qDebug() <<"CurUs:"<< CurUs;

            imshow("DrawImage", DrawImage);
            //emit ShowImageSig(DrawImage, "DrawImage");
            //waitKey();

        } catch (cv::Exception &e) {
            qDebug() <<"imread:"<< e.what();
            return ;
        }

        qDebug() << "End";
    }
}

void OcrTest::SplitContours(int SplitContours_k, double SplitContours_t)
{
    if (!ImagePath.isEmpty())
    {
        std::string item = ImagePath.toStdString();

        try {
             std::chrono::time_point<std::chrono::high_resolution_clock> TimeStart(std::chrono::high_resolution_clock::now());

            Mat InImage = cv::imread( item, IMREAD_COLOR );
            if(InImage.empty())
            {
                qDebug() <<"imread failed:"<< item.c_str();
                return ;
            }
            //imshow("In", tmpImage);
            cv::Mat TmpImage;
            //ProcImageMap["BinImage"] = cv::Mat();
            //unevenLightCompensate( tmpImage, 32 );
            //imshow("In1", tmpImage);

            if(InImage.depth() != 8)
            {
                 qDebug() <<"depth:"<< InImage.depth();
            }

            if(InImage.channels() !=3 || InImage.channels() != 1)
            {

            }

            cv::bilateralFilter(InImage, TmpImage, 5, 100, 100);
            cv::Canny(TmpImage, ProcImageMap["BinImage"], 50, 100, 3, true);
            cv::threshold(ProcImageMap["BinImage"], ProcImageMap["BinImage"], 70, 255, cv::THRESH_TRIANGLE);

//            Mat element = getStructuringElement(MORPH_RECT, Size(3, 3) ); // 5、高级形态学变化，闭操作
//            cv::morphologyEx( BinImage,BinImage, MORPH_CLOSE, element);

//            Mat ThinImage = thinImage(BinImage);
//            BinImage = ThinImage * 255;

            //imshow("BinImage", ProcImageMap["BinImage"]);
            //imshow("ThinImage", ThinImage);

            std::vector< std::vector<cv::Point> > contours;
            vector<cv::Vec4i> hierarchy;
            findContours(ProcImageMap["BinImage"], contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));

            ProcImageMap["DrawImage"] = InImage;

            //GetPoint1( contours, DrawImage);
            //GetPoint2( contours, DrawImage );

            for(size_t idx=0; idx<contours.size(); idx++)
            {
                if(contours[idx].size() < 50)
                {
                    continue;
                }

                Scalar LineColor(RNG(255), RNG(255), RNG(255));
                drawContours(ProcImageMap["DrawImage"], contours, idx, LineColor);

                //遍历轮廓，求出所有支撑角度
                vector<Point> sharpContours = findSharpCorners(contours[idx], SplitContours_k, SplitContours_t);
                for (int i = 0; i < sharpContours.size(); i++)
                {
                    circle(ProcImageMap["DrawImage"], sharpContours[i], 5, LineColor, 2);
                }
            }

            long long CurUs = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - TimeStart).count() / 1000.f;
            qDebug() <<"CurUs:"<< CurUs;

            //imshow("DrawImage", ProcImageMap["DrawImage"]);
            //emit ShowImageSig(DrawImage, "DrawImage");
            //waitKey();

        } catch (cv::Exception &e) {
            qDebug() <<"imread:"<< e.what();
            return ;
        }

        qDebug() << "End";
    }
}

void OcrTest::on_SplitContours_clicked()
{
    ImagePath = QFileDialog::getOpenFileName();
    int SplitContours_k = ui->SplitContours_k->value();
    double SplitContours_t = ui->SplitContours_t->value();

    SplitContours(SplitContours_k, SplitContours_t);
    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
}

void OcrTest::on_SplitContours_k_valueChanged(int arg1)
{
    double SplitContours_t = ui->SplitContours_t->value();

    SplitContours(arg1, SplitContours_t);
    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
}

void OcrTest::on_SplitContours_t_valueChanged(double arg1)
{
    int SplitContours_k = ui->SplitContours_k->value();

    SplitContours(SplitContours_k, arg1);
    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
}

void OcrTest::SlectectImageToShowSlot(const std::string ImageId, const std::string objectName)
{
    if(objectName != std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/)
    {
        return;
    }

    if(ProcImageMap.empty() || (ProcImageMap.find(ImageId) == ProcImageMap.end()))
    {
        return ;
    }
    //qDebug() <<"ShowImageSig: "<< ImageId.c_str();
    emit ShowImageSig(ProcImageMap[ImageId], ImageId);
}

void OcrTest::on_Ed_Test_clicked()
{
    //***************************** ED Edge Segment Detection *****************************
    //Detection of edge segments from an input image
    QString ImagePath = QFileDialog::getOpenFileName();
    if (ImagePath.isEmpty())
    {
        return ;
    }

    std::string item = ImagePath.toStdString();

    ProcImageMap["SourceImage"] = imread(item, 0);
    if(ProcImageMap["SourceImage"].empty())
    {
        qDebug() << "获取图像失败";
        return ;
    }
    //Call ED constructor
    ED testED = ED(ProcImageMap["SourceImage"], SOBEL_OPERATOR, 36, 8, 1, 10, 1.0, true); // apply ED algorithm

    //Show resulting edge image
    ProcImageMap["EdgeImage"] = testED.getEdgeImage();

    //Output number of segments
    int noSegments = testED.getSegmentNo();
    qInfo()<< "Number of edge segments: " << noSegments;
    //std::cout << "Number of edge segments: " << noSegments << std::endl;

    //Get edges in segment form (getSortedSegments() gives segments sorted w.r.t. legnths)
    std::vector< std::vector<Point> > segments = testED.getSegments();


    //***************************** EDLINES Line Segment Detection *****************************
    //Detection of line segments from the same image
    EDLines testEDLines = EDLines(ProcImageMap["SourceImage"]);
    ProcImageMap["LineImage1"] = testEDLines.getLineImage();	//draws on an empty image

    //Detection of lines segments from edge segments instead of input image
    //Therefore, redundant detection of edge segmens can be avoided
    testEDLines = EDLines(testED);
    ProcImageMap["LineImage2"] = testEDLines.drawOnImage();	//draws on the input image

    //Acquiring line information, i.e. start & end points
    vector<LS> lines = testEDLines.getLines();
    int noLines = testEDLines.getLinesNo();
    qInfo()<< "Number of line segments: " << noLines;
    //std::cout << "Number of line segments: " << noLines << std::endl;

    //************************** EDPF Parameter-free Edge Segment Detection **************************
    // Detection of edge segments with parameter free ED (EDPF)

    EDPF testEDPF = EDPF(ProcImageMap["SourceImage"]);
    ProcImageMap["EdgeImagePF"] = testEDPF.getEdgeImage();
    qInfo()<< "Number of edge segments found by EDPF: " << testEDPF.getSegmentNo();
    //cout << "Number of edge segments found by EDPF: " << testEDPF.getSegmentNo() << endl;
    //***************************** EDCIRCLES Circle Segment Detection *****************************
    //Detection of circles directly from the input image

    EDCircles testEDCircles = EDCircles(ProcImageMap["SourceImage"]);
    ProcImageMap["CircleImage1"] = testEDCircles.drawResult(false, ImageStyle::CIRCLES);

    //Detection of circles from already available EDPF or ED image
    testEDCircles = EDCircles(testEDPF);

    //Get circle information as [cx, cy, r]
    vector<mCircle> circles = testEDCircles.getCircles();

    //Get ellipse information as [cx, cy, a, b, theta]
    vector<mEllipse> ellipses = testEDCircles.getEllipses();

    //Circles and ellipses will be indicated in green and red, resp.
    ProcImageMap["CircleImage2"] = testEDCircles.drawResult(true, ImageStyle::BOTH);

    int noCircles = testEDCircles.getCirclesNo();
    qInfo()<< "Number of circles: " << noCircles;
    //std::cout << "Number of circles: " << noCircles << std::endl;

    //*********************** EDCOLOR Edge Segment Detection from Color Images **********************

    ProcImageMap["SourceImageColor"] = imread(item);
    EDColor testEDColor = EDColor(ProcImageMap["SourceImageColor"], 36, 4, 1.5, true); //last parameter for validation
    ProcImageMap["ColorEdgeImage"] = testEDColor.getEdgeImage();
    qInfo()<< "Number of edge segments detected by EDColor: " << testEDColor.getSegmentNo();
    //cout << "Number of edge segments detected by EDColor: " << testEDColor.getSegmentNo() << endl;

    // get lines from color image
    EDLines colorLine = EDLines(testEDColor);
    ProcImageMap["ColorLine"] =colorLine.getLineImage();
    qInfo()<< "Number of line segments: " << colorLine.getLinesNo();
    //std::cout << "Number of line segments: " << colorLine.getLinesNo() << std::endl;

    // get circles from color image
    EDCircles colorCircle = EDCircles(testEDColor);
    // TO DO :: drawResult doesnt overlay (onImage = true) when input is from EDColor
    ProcImageMap["ColorCircle"] = colorCircle.drawResult(false, ImageStyle::BOTH);
    qInfo()<< "Number of line segments: " << colorCircle.getCirclesNo();
    //std::cout << "Number of line segments: " << colorCircle.getCirclesNo() << std::endl;

    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
}

//void OcrTest::on_ShapeMatch_clicked()
//{
//    QString ImagePath = QFileDialog::getOpenFileName();
//    if (ImagePath.isEmpty())
//    {
//        return ;
//    }

//    std::string prefix("D:/awei/project/MainFrame/");
//    std::string item = ImagePath.toStdString();

//    ProcImageMap["SourceImage"] = imread(item, 0);
//    if(ProcImageMap["SourceImage"].empty())
//    {
//        qDebug() << "获取图像失败";
//        return ;
//    }
//    assert(!ProcImageMap["SourceImage"].empty() && "check your img path");
//    //shape_based_matching::shapeInfo_producer shapes(ProcImageMap["SourceImage"]);
//    Mat& test_img = ProcImageMap["SourceImage"];
//    assert(!test_img.empty() && "check your img path");

//    line2Dup::Detector detector(128, {4, 8});
//    //    //Timer timer;
//    //    auto matches = detector.match(img, 90);
//    //   // timer.out();

//    //    qInfo() <<"matches.size(): " << matches.size();

//    std::vector<std::string> ids;
//    ids.push_back("test");
//    detector.readClasses(ids, prefix+"case1/%s_templ.yaml");

//    // angle & scale are saved here, fetched by match id
//    auto infos = shape_based_matching::shapeInfo_producer::load_infos(prefix + "case1/test_info.yaml");

//    int padding = 50;
//    cv::Mat padded_img = cv::Mat(test_img.rows + 2*padding,
//                                 test_img.cols + 2*padding, test_img.type(), cv::Scalar::all(0));
//    test_img.copyTo(padded_img(Rect(padding, padding, test_img.cols, test_img.rows)));

//    int stride = 16;
//    int n = padded_img.rows/stride;
//    int m = padded_img.cols/stride;
//    Rect roi(0, 0, stride*m , stride*n);
//    ProcImageMap["img"] = padded_img(roi).clone();
//    //ProcImageMap["img"] = test_img.clone();
//    Mat &img = ProcImageMap["img"];
//    assert(img.isContinuous());
//    qInfo()  << "test img size: " << img.rows * img.cols;

//    auto matches = detector.match(img, 70, ids);

//    if(img.channels() == 1)
//        cvtColor(img, img, cv::COLOR_GRAY2BGR);

//    qInfo()  << "matches.size(): " << matches.size();
//    size_t top5 = 1;
//    if(top5>matches.size()) top5=matches.size();
//    for(size_t i=0; i<top5; i++){
//        auto match = matches[i];
//        auto templ = detector.getTemplates("test",
//                                           match.template_id);

//        // 270 is width of template image
//        // 100 is padding when training
//        // tl_x/y: template croping topleft corner when training

//        float r_scaled = 270/2.0f*infos[match.template_id].scale;

//        // scaling won't affect this, because it has been determined by warpAffine
//        // cv::warpAffine(src, dst, rot_mat, src.size()); last param
//        float train_img_half_width = 270/2.0f + 100;

//        // center x,y of train_img in test img
//        float x =  match.x - templ[0].tl_x + train_img_half_width;
//        float y =  match.y - templ[0].tl_y + train_img_half_width;

//        cv::Vec3b randColor;
//        randColor[0] = rand()%155 + 100;
//        randColor[1] = rand()%155 + 100;
//        randColor[2] = rand()%155 + 100;
//        for(int i=0; i<templ[0].features.size(); i++){
//            auto feat = templ[0].features[i];
//            cv::circle(img, {feat.x+match.x, feat.y+match.y}, 3, randColor, -1);
//        }

//        cv::putText(img, to_string(int(round(match.similarity))),
//                    Point(match.x+r_scaled-10, match.y-3), FONT_HERSHEY_PLAIN, 2, randColor);

//        cv::RotatedRect rotatedRectangle({x, y}, {2*r_scaled, 2*r_scaled}, -infos[match.template_id].angle);

//        cv::Point2f vertices[4];
//        rotatedRectangle.points(vertices);
//        for(int i=0; i<4; i++){
//            int next = (i+1==4) ? 0 : (i+1);
//            cv::line(img, vertices[i], vertices[next], randColor, 2);
//        }

//        qInfo()   << "\nmatch.template_id: " << match.template_id;
//        qInfo()   << "match.similarity: " << match.similarity;
//    }

//    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
//}

//void OcrTest::on_ShapeTrain_clicked()
//{
//    QString ImagePath = QFileDialog::getOpenFileName();
//    if (ImagePath.isEmpty())
//    {
//        return ;
//    }

//    std::string item = ImagePath.toStdString();
//    std::string prefix("D:/awei/project/MainFrame/");
//    ProcImageMap["SourceImage"] = imread(item, 0);
//    if(ProcImageMap["SourceImage"].empty())
//    {
//        qDebug() << "获取图像失败";
//        return ;
//    }
//    line2Dup::Detector detector(128, {4, 8});

//    assert(!ProcImageMap["SourceImage"].empty() && "check your img path");
//    Mat& img = ProcImageMap["SourceImage"];
//    //Rect roi(130, 110, 270, 270);
//    //img = img(roi).clone();
//    Mat mask = Mat(img.size(), CV_8UC1, {255});

//    // padding to avoid rotating out
//    int padding = 0;
//    cv::Mat padded_img = cv::Mat(img.rows + 2*padding, img.cols + 2*padding, img.type(), cv::Scalar::all(0));
//    img.copyTo(padded_img(Rect(padding, padding, img.cols, img.rows)));

//    cv::Mat padded_mask = cv::Mat(mask.rows + 2*padding, mask.cols + 2*padding, mask.type(), cv::Scalar::all(0));
//    mask.copyTo(padded_mask(Rect(padding, padding, img.cols, img.rows)));

//    shape_based_matching::shapeInfo_producer shapes(padded_img, padded_mask);
//    shapes.angle_range = {0, 360};
//    shapes.angle_step = 1;
//    shapes.produce_infos();
//    std::vector<shape_based_matching::shapeInfo_producer::Info> infos_have_templ;
//    string class_id = "test";
//    for(auto& info: shapes.infos){
//        ProcImageMap["train"] = shapes.src_of(info);
//        emit ShowImageSig(ProcImageMap["train"], "train");
//        //waitKey(1);

//        qInfo() << "info.angle: " << info.angle;
//        int templ_id = detector.addTemplate(shapes.src_of(info), class_id, shapes.mask_of(info), 64);
//        qInfo() << "templ_id: " << templ_id;
//        if(templ_id != -1){
//            infos_have_templ.push_back(info);
//        }
//    }
//    detector.writeClasses(prefix+"case1/%s_templ.yaml");
//    shapes.save_infos(infos_have_templ, prefix + "case1/test_info.yaml");
//    qInfo() << "train end" ;
//}


void OcrTest::on_ShapeMatch_clicked()
{
    QString ImagePath = QFileDialog::getOpenFileName();
    if (ImagePath.isEmpty())
    {
        return ;
    }

    std::string prefix("D:/awei/project/MainFrame/");
    std::string item = ImagePath.toStdString();

    ProcImageMap["target"] = imread(item, IMREAD_GRAYSCALE);
    if(ProcImageMap["target"].empty())
    {
        qDebug() << "获取图像失败";
        return ;
    }
    assert(!ProcImageMap["target"].empty() && "check your img path");
    //shape_based_matching::shapeInfo_producer shapes(ProcImageMap["SourceImage"]);
    Mat& test_img = ProcImageMap["target"];

    line2Dup::Detector detector(64, {4, 8});
    //    //Timer timer;
    //    auto matches = detector.match(img, 90);
    //   // timer.out();

    //    qInfo() <<"matches.size(): " << matches.size();

    std::vector<std::string> ids;
    ids.push_back("Mark");
    detector.readClasses(ids, prefix+"case1/%s_templ.yaml");

    // angle & scale are saved here, fetched by match id
    auto infos = shape_based_matching::shapeInfo_producer::load_infos(prefix + "case1/Mark_info.yaml");

//    int padding = 50;
//    cv::Mat padded_img = cv::Mat(test_img.rows + 2*padding,
//                                 test_img.cols + 2*padding, test_img.type(), cv::Scalar::all(0));
//    test_img.copyTo(padded_img(Rect(padding, padding, test_img.cols, test_img.rows)));

//    int stride = 16;
//    int n = padded_img.rows/stride;
//    int m = padded_img.cols/stride;
//    Rect roi(0, 0, stride*m , stride*n);
//    ProcImageMap["img"] = padded_img(roi).clone();
//    //ProcImageMap["img"] = test_img.clone();
//    Mat &img = ProcImageMap["img"];

    Mat &img = ProcImageMap["target"];
    assert(img.isContinuous());
    qInfo()  << "test img size: " << img.rows * img.cols;

    auto matches = detector.match(img, 70, ids);

    if(img.channels() == 1)
        cvtColor(img, img, cv::COLOR_GRAY2BGR);

    qInfo()  << "matches.size(): " << matches.size();
    size_t top5 = 1;
    if(top5>matches.size())
        top5=matches.size();

    for(size_t i=0; i<top5; i++){
        auto match = matches[i];
        auto templ = detector.getTemplates("Mark", match.template_id);

        int w = 0, h = 0;
        detector.getTemplateSize(w, h);
        // 270 is width of template image
        // 100 is padding when training
        // tl_x/y: template croping topleft corner when training
        float r_scaled = w/2.0f*infos[match.template_id].scale;

        // scaling won't affect this, because it has been determined by warpAffine
        // cv::warpAffine(src, dst, rot_mat, src.size()); last param
        float train_img_half_width = w/2.0f;

        // center x,y of train_img in test img
        float x =  match.x - templ[0].tl_x + train_img_half_width;
        float y =  match.y - templ[0].tl_y + train_img_half_width;

        cv::Vec3b randColor;
        randColor[0] = rand()%155 + 100;
        randColor[1] = rand()%155 + 100;
        randColor[2] = rand()%155 + 100;
        for(int i=0; i<templ[0].features.size(); i++){
            auto feat = templ[0].features[i];
            cv::circle(img, {feat.x+match.x, feat.y+match.y}, 3, randColor, -1);
        }

        cv::putText(img, to_string(int(round(match.similarity))),
                    Point(match.x+w*infos[match.template_id].scale-10, match.y-3), FONT_HERSHEY_PLAIN, 2, randColor);

        cv::RotatedRect rotatedRectangle({x, y}, {w*infos[match.template_id].scale, h*infos[match.template_id].scale}, -infos[match.template_id].angle);

        cv::Point2f vertices[4];
        rotatedRectangle.points(vertices);
        for(int i=0; i<4; i++){
            int next = (i+1==4) ? 0 : (i+1);
            cv::line(img, vertices[i], vertices[next], randColor, 2);
        }

        qInfo()   << "\nmatch.template_id: " << match.template_id;
        qInfo()   << "match.similarity: " << match.similarity;
    }

    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
}

void OcrTest::on_ShapeTrain_clicked()
{
    QString ImagePath = QFileDialog::getOpenFileName();
    if (ImagePath.isEmpty())
    {
        return ;
    }

    std::string item = ImagePath.toStdString();
    std::string prefix("D:/awei/project/MainFrame/");
    ProcImageMap["template"] = imread(item, 0);
    if(ProcImageMap["template"].empty())
    {
        qDebug() << "获取图像失败";
        return ;
    }
    line2Dup::Detector detector(64, {4, 8});

    assert(!ProcImageMap["template"].empty() && "check your img path");
    Mat& img = ProcImageMap["template"];
    Mat mask = Mat(img.size(), CV_8UC1, {255});

    // padding to avoid rotating out
    int padding = 10;
    cv::Mat padded_img = cv::Mat(img.rows + 2*padding, img.cols + 2*padding, img.type(), cv::Scalar::all(0));
    img.copyTo(padded_img(Rect(padding, padding, img.cols, img.rows)));

    cv::Mat padded_mask = cv::Mat(mask.rows + 2*padding, mask.cols + 2*padding, mask.type(), cv::Scalar::all(0));
    mask.copyTo(padded_mask(Rect(padding, padding, img.cols, img.rows)));

    shape_based_matching::shapeInfo_producer shapes(padded_img, padded_mask);
    shapes.angle_range = {-5, 5};
    shapes.angle_step = 0.1;
    shapes.produce_infos();
    std::vector<shape_based_matching::shapeInfo_producer::Info> infos_have_templ;
    string class_id = "Mark";
    for(auto& info: shapes.infos){
        ProcImageMap["train"] = shapes.src_of(info);
        emit ShowImageSig(ProcImageMap["train"], "train");
        //waitKey(1);

        qInfo() << "info.angle: " << info.angle;
        int templ_id = detector.addTemplate(shapes.src_of(info), class_id, shapes.mask_of(info), 64);
        qInfo() << "templ_id: " << templ_id;
        if(templ_id != -1){
            infos_have_templ.push_back(info);
        }
    }
    detector.setTemplateSize(padded_img.cols, padded_img.rows);
    detector.writeClasses(prefix+"case1/%s_templ.yaml");
    shapes.save_infos(infos_have_templ, prefix + "case1/Mark_info.yaml");
    qInfo() << "train end" ;

    emit UpdateIconListSig(ProcImageMap, std::to_string((unsigned long long )this) /*this->objectName().toStdString()*/);
}

void OcrTest::on_RectifyPurcC_clicked()
{
    RectifyImageWithText( 0 );
}

void OcrTest::on_RectifyOpencvEdge_clicked()
{
    RectifyImageWithText( 1 );
}

void OcrTest::on_RectifyOpencvLine_clicked()
{
    RectifyImageWithText( 2 );
}

void OcrTest::RectifyImageWithText(int type)
{
    const string InputImage = ui->InputImagePath->text().toUtf8().data();
    const string OutImage = ui->OutputImagePath->text().toUtf8().data();

    if(InputImage.empty() || OutImage.empty())
    {
        qWarning() << u8"输入路径或输出路径为空！";
        return ;
    }

    setUseOptimized( true );
    bool bShowDlg = true;
    switch(type)
    {
    case 1:
        GetContoursPic(InputImage.c_str(), OutImage.c_str(), bShowDlg);
        break;

    case 2:
        ImageRecify(InputImage.c_str(), OutImage.c_str(), ui->SetThreshold->value(), bShowDlg);
        break;

    default:
    case 0:
    {
        char pDstFileName[1024] = {0};
        Rectify(InputImage.c_str(), pDstFileName, bShowDlg);
    }
        break;
    }
}

void OcrTest::on_btnSetInputImage_clicked()
{
    QString path = QFileDialog::getOpenFileName(this, u8"指定输入图片");
    if(!path.isEmpty())
    {
        ui->InputImagePath->setText(path);
    }
}

void OcrTest::on_btnSetOutputImage_clicked()
{
    QString path = QFileDialog::getSaveFileName(this, u8"指定输出图片", 0, "*.png");
    if(!path.isEmpty())
    {
        ui->OutputImagePath->setText(path);
    }
}
